package utils

import (
	"fmt"
	"reflect"
	"strings"
	"unicode"
)

/**
 * @Author: minglic
 * @description: 调用结构体的方法，并返回字符串
 * @param {any} obj
 * @param {string} methodName
 * @return {*}
 */
func GetEntityCollName(obj any) (string, error) {
	var err error
	collname, _ := CallMethodGetStringIfExists(obj, "CollectionName")
	if collname == "" {
		collname, err = GetStructName(obj)
		if err != nil {
			return "", err
		}
		collname = LowerCaseFirstLetter(collname)
	}
	return collname, nil
}

/**
 * @Author: minglic
 * @description: 将字符串的首字母转为小写
 * @param {string} s
 * @return {*}
 */
func LowerCaseFirstLetter(s string) string {
	if s == "" {
		return ""
	}
	r := []rune(s)
	r[0] = unicode.ToLower(r[0])
	return string(r)
}

/**
 * @Author: minglic
 * @description: 调用结构体的方法，并返回字符串
 * @param {any} obj
 * @param {string} methodName
 * @return {*}
 */
func CallMethodGetStringIfExists(obj any, methodName string) (string, error) {
	method := reflect.ValueOf(obj).MethodByName(methodName)
	if method.IsValid() && method.Kind() == reflect.Func {
		result := method.Call(nil)
		if len(result) > 0 {
			return result[0].String(), nil
		}
	}

	return "", nil
}

/**
 * @Author: minglic
 * @description: 获得struct的名称
 * @param {any} model
 * @return {*}
 */
func GetStructName(model any) (string, error) {
	t := reflect.TypeOf(model)

	// 如果是指针，获取指针指向的元素的类型
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}

	// 如果是切片，获取切片元素的类型
	if t.Kind() == reflect.Slice {
		t = t.Elem()
	}

	// 再次检查是否指向结构体
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}

	// 最终，如果是结构体，返回其名称
	if t.Kind() == reflect.Struct {
		return t.Name(), nil
	}

	return "", fmt.Errorf("不是结构体也不是结构体切片")
}

func GetFieldString(model any, fieldName string) (string, error) {
	field, err := GetField(model, fieldName)
	if err != nil {
		return "", err
	}

	if field.Kind() != reflect.String {
		return "", fmt.Errorf("不是字符串类型")
	}

	return field.String(), nil
}

// GetFieldAny 从任意类型的值中提取指定字段路径的值。
// 支持通过点分隔的嵌套字段路径，包括匿名字段。
func GetFieldAny(value any, fieldPath string) (any, error) {
	// 获取value的反射值对象
	val := reflect.ValueOf(value)
	// 如果是指针，则解引用
	if val.Kind() == reflect.Ptr {
		val = val.Elem()
	}

	// 按点分割字段路径
	parts := strings.Split(fieldPath, ".")
	// 遍历字段路径的每一部分
	for _, part := range parts {
		// 尝试通过字段名获取字段
		field := val.FieldByName(part)
		if !field.IsValid() {
			// 如果字段无效，检查是否为匿名字段（嵌入的结构体）
			if val.Kind() == reflect.Struct {
				for i := 0; i < val.NumField(); i++ {
					fieldType := val.Type().Field(i)
					// 如果是匿名字段，则递归查找
					if fieldType.Anonymous {
						field = val.Field(i).FieldByName(part)
						if field.IsValid() {
							break
						}
					}
				}
			}
		}

		// 如果字段仍然无效，则返回错误
		if !field.IsValid() {
			return nil, fmt.Errorf("未找到字段 '%s'", fieldPath)
		}

		// 更新val为找到的字段，以便继续查找嵌套字段
		val = field
	}

	// 返回找到的字段值
	return val.Interface(), nil
}

// func GetFieldAny(model any, fieldName string) (any, error) {

// 	if strings.Contains(fieldName, ".") {
// 		fields := strings.Split(fieldName, ".")
// 		field, err := GetField(model, fields[0])
// 		if err != nil {
// 			return "", err
// 		}

// 		if field.Kind() == reflect.Ptr {
// 			if field.IsNil() {
// 				return nil, nil
// 			}
// 			return GetFieldAny(field.Interface(), fields[1])
// 		}

// 		return GetFieldAny(field.Interface(), fields[1])

// 	}

// 	field, err := GetField(model, fieldName)
// 	if err != nil {
// 		return "", err
// 	}

// 	return field.Interface(), nil
// }

func GetField(model any, fieldName string) (*reflect.Value, error) {

	// 获取指针指向的值的反射类型
	valueType := reflect.TypeOf(model).Elem()

	// 获取字段"Name"的值
	_, ok := valueType.FieldByName(fieldName)
	if !ok {
		return nil, fmt.Errorf("字段不存在:%s", fieldName)
	}

	nameValue := reflect.ValueOf(model).Elem().FieldByName(fieldName)

	return &nameValue, nil
}

func SetField(obj, data any, fieldName string) error {
	// 使用反射给结构体的指针属性赋值
	value := reflect.ValueOf(obj).Elem()  // 获取结构体的可设置值
	field := value.FieldByName(fieldName) // 获取属性字段
	if field.IsValid() && field.CanSet() && field.Kind() == reflect.Ptr {
		field.Set(reflect.ValueOf(data)) // 给指针属性赋值
	} else {
		return fmt.Errorf("批不到属性:%s", fieldName)
	}
	return nil
}
